package com.buss.util.http;

import org.apache.commons.lang.StringUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 请求基础服务类
 * 
 * @author bin
 * @date 2014-06-01 下午2:03:13
 */
@SuppressWarnings("deprecation")
public final class RequestService {

	private static final Logger LOG = Logger.getLogger(RequestService.class);
 
	private static final String HTTP_CHARSET = "utf-8";
	
	private RequestService() {
	}

	public static String sendTDGet(String url, Map params, String charset) {
		String errroMsg = "";
		long startTime = System.currentTimeMillis();
		long endTime = startTime;
		if (url == null || StringUtils.isEmpty(url)) {
			return null;
		}
		List qparams = getParamsList(params);
		if (qparams != null && qparams.size() > 0) {
			charset = (charset == null ? "CHARSET_GBK" : charset);
			String formatParams = URLEncodedUtils.format(qparams, charset);
			url = (url.indexOf("?")) < 0 ? (url + "?" + formatParams) : (url
					.substring(0, url.indexOf("?") + 1) + formatParams);
		}
		LOG.info("GET请求的最终URL:----->"+url);
		DefaultHttpClient httpclient = getDefaultHttpClient(charset);
		HttpGet hg = new HttpGet(url);
		hg.setHeader("Content-Type", "application/x-www-form-urlencoded");
		// 发送请求，得到响应
		String responseStr = null;
		try {
			responseStr = (String)httpclient.execute(hg, responseHandler);
			//responseStr = HttpClientUtil.getHttpClient().execute(hg, responseHandler);
			endTime = System.currentTimeMillis();
			//LOG.info("目标系统响应：\n " + responseStr);
			LOG.info("目标系统响应：\n " + "成功!");
		} catch (HttpHostConnectException e) {
			errroMsg = "目标系统拒绝访问，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (ConnectException e) {
			errroMsg = "连接目标系统超时，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (Exception e) {
			errroMsg = "调用目标系统时出现异常!";
			LOG.error(errroMsg, e);
		} finally {
			LOG.info("接口执行耗时(毫秒)： " + (endTime - startTime));
			//abortConnection(hg, HttpClientUtil.getHttpClient());
			abortConnection(hg, httpclient);
		}
		return responseStr;
	}
	
	/**
	* @author: A-Do
	* @date: 2016-4-8 下午2:30:10
	* @Title: sendTDPost
	* @Description: 同盾专用
	* @param @param httpServiceURL
	* @param @param params
	* @param @return    设定文件 
	* @return String    返回类型 
	* @throws 
	*/
	public static String sendTDPost(String httpServiceURL, Map<String,String> params) {
		return sendTDPost(httpServiceURL, params, HTTP_CHARSET, HTTP_CHARSET);
	}
	
	/**
	* @author: A-Do
	* @date: 2016-4-8 下午2:30:22
	* @Title: sendTDPost
	* @Description: 同盾专用 
	* @param @param httpServiceURL
	* @param @param params
	* @param @param reqCharSet
	* @param @param respCharSet
	* @param @return    设定文件 
	* @return String    返回类型 
	* @throws 
	*/
	public static String sendTDPost(String httpServiceURL, Map<String, String> params, String reqCharSet, String respCharSet) {

		long startTime = System.currentTimeMillis();
		long endTime = startTime;
		String result = "";
		String errroMsg = "";
		
		try {
			
			HttpPost httpPost = new HttpPost(httpServiceURL);
			httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
			List<NameValuePair> nvps = new ArrayList <NameValuePair>();

			for(Entry<String, String> entry : params.entrySet()){
				nvps.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
			}
			
			httpPost.setEntity(new UrlEncodedFormEntity(nvps, reqCharSet));
			HttpResponse response = HttpClientUtil.getHttpClient().execute(httpPost);
			HttpEntity entity = response.getEntity();
			result = EntityUtils.toString(response.getEntity(), respCharSet);
			EntityUtils.consume(entity);
			
			endTime = System.currentTimeMillis();
			
		}catch (HttpHostConnectException e) {
			errroMsg = "目标系统拒绝访问，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (ConnectException e) {
			errroMsg = "连接目标系统超时，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (UnsupportedEncodingException e) {
			errroMsg = "编码异常!";
			LOG.error(errroMsg, e);
		}catch (Exception e) {
			errroMsg = "调用目标系统时出现异常!";
			LOG.error(errroMsg, e);
		}finally {
			LOG.info("接口执行耗时(毫秒)： " + (endTime - startTime));
		}
		return result;
	}

	/**
	 * 向指定系统发送Post请求，参数类型为String
	 * 
	 * @param httpServiceURL
	 * @param context
	 * @return
	 */
	public static String sendPost(String httpServiceURL, String context) {
		return sendPost(httpServiceURL, context, HTTP_CHARSET, HTTP_CHARSET);
	}
	
	/**
	 * 向指定系统发送Post请求，参数类型为String
	 * 
	 * @param httpServiceURL
	 * @param context
	 * @return
	 */
	public static String sendPost(String httpServiceURL, String context, String reqCharSet, String respCharSet) {

		long startTime = System.currentTimeMillis();
		long endTime = startTime;
		String result = "";
		String errroMsg = "";
		
		try {
			
			HttpPost httpPost = new HttpPost(httpServiceURL);
			
			if(StringUtils.isNotBlank(context)){
				httpPost.setEntity(new StringEntity(context, reqCharSet));
			}
			
			HttpResponse response = HttpClientUtil.getHttpClient().execute(httpPost);
			HttpEntity entity = response.getEntity();
			result = EntityUtils.toString(response.getEntity(), respCharSet);
			EntityUtils.consume(entity);
			
			endTime = System.currentTimeMillis();
			
		}catch (HttpHostConnectException e) {
			errroMsg = "目标系统拒绝访问，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (ConnectException e) {
			errroMsg = "连接目标系统超时，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (Exception e) {
			errroMsg = "调用目标系统时出现异常!";
			LOG.error(errroMsg, e);
		}finally {
			LOG.info("接口执行耗时(毫秒)： " + (endTime - startTime));
		}
		return result;
	}


	/**
	 * 向指定系统发送Post请求，参数类型为Map<String, Object>
	 * 
	 * @param httpServiceURL
	 * @param params
	 * @param reqCharSet  请求编码
	 * @param respCharSet 响应编码
	 * @return
	 */
	public static String sendPost(String httpServiceURL, Map<String, Object> params, String reqCharSet, String respCharSet) {

		long startTime = System.currentTimeMillis();
		long endTime = startTime;
		String result = "";
		String errroMsg = "";
		
		try {
			
			HttpPost httpPost = new HttpPost(httpServiceURL);
			List<NameValuePair> nvps = new ArrayList <NameValuePair>();

			for(Entry<String, Object> entry : params.entrySet()){
				nvps.add(new BasicNameValuePair(entry.getKey(),entry.getValue().toString()));
			}
			
			httpPost.setEntity(new UrlEncodedFormEntity(nvps, reqCharSet));
			HttpResponse response = HttpClientUtil.getHttpClient().execute(httpPost);
			HttpEntity entity = response.getEntity();
			result = EntityUtils.toString(response.getEntity(), respCharSet);
			EntityUtils.consume(entity);
			
			endTime = System.currentTimeMillis();
			
		}catch (HttpHostConnectException e) {
			errroMsg = "目标系统拒绝访问，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (ConnectException e) {
			errroMsg = "连接目标系统超时，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (UnsupportedEncodingException e) {
			errroMsg = "编码异常!";
			LOG.error(errroMsg, e);
		}catch (Exception e) {
			errroMsg = "调用目标系统时出现异常!";
			LOG.error(errroMsg, e);
		}finally {
			LOG.info("接口执行耗时(毫秒)： " + (endTime - startTime));
		}
		return result;
	}
	public static String sendPost(String httpServiceURL, List<NameValuePair> nvps, String reqCharSet) {

		long startTime = System.currentTimeMillis();
		long endTime = startTime;
		String result = "";
		String errroMsg = "";
		
		try {
			
			HttpPost httpPost = new HttpPost(httpServiceURL);
			
			httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
			HttpResponse response = HttpClientUtil.getHttpClient().execute(httpPost);
			HttpEntity entity = response.getEntity();
			result = EntityUtils.toString(response.getEntity(), "UTF-8");
			EntityUtils.consume(entity);
			
			endTime = System.currentTimeMillis();
			
		}catch (HttpHostConnectException e) {
			errroMsg = "目标系统拒绝访问，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (ConnectException e) {
			errroMsg = "连接目标系统超时，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (UnsupportedEncodingException e) {
			errroMsg = "编码异常!";
			LOG.error(errroMsg, e);
		}catch (Exception e) {
			errroMsg = "调用目标系统时出现异常!";
			LOG.error(errroMsg, e);
		}finally {
			LOG.info("接口执行耗时(毫秒)： " + (endTime - startTime));
		}
		return result;
	}

	/**
	* @Description: TODO
	* @param url
	* @param params
	* @param charset
	* @return
	* @author: A-Do
	* @date: 2015-8-27 下午1:58:49
	*/
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static String sendGet(String url, Map params, String charset) {
		String errroMsg = "";
		long startTime = System.currentTimeMillis();
		long endTime = startTime;
		
		if (url == null || StringUtils.isEmpty(url)) {
			return null;
		} 
		List qparams = getParamsList(params);
		if (qparams != null && qparams.size() > 0) {
			charset = (charset == null ? "CHARSET_GBK" : charset);
			String formatParams = URLEncodedUtils.format(qparams, charset);
			url = (url.indexOf("?")) < 0 ? (url + "?" + formatParams) : (url
					.substring(0, url.indexOf("?") + 1) + formatParams);
		}
		LOG.info("GET请求的最终URL:----->"+url);
		DefaultHttpClient httpclient = getDefaultHttpClient(charset);
		HttpGet hg = new HttpGet(url);
		// 发送请求，得到响应
		String responseStr = null;
		try {
			responseStr = (String)httpclient.execute(hg, responseHandler);
			//responseStr = HttpClientUtil.getHttpClient().execute(hg, responseHandler);
			endTime = System.currentTimeMillis();
			//LOG.info("目标系统响应：\n " + responseStr);
			LOG.info("目标系统响应：\n " + "成功!");
		} catch (HttpHostConnectException e) {
			errroMsg = "目标系统拒绝访问，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (ConnectException e) {
			errroMsg = "连接目标系统超时，请联系相关技术人员!";
			LOG.error(errroMsg, e);
		} catch (Exception e) {
			errroMsg = "调用目标系统时出现异常!";
			LOG.error(errroMsg, e);
		} finally {
			LOG.info("接口执行耗时(毫秒)： " + (endTime - startTime));
			//abortConnection(hg, HttpClientUtil.getHttpClient());
			abortConnection(hg, httpclient);
		}
		return responseStr;
	}
	
	
	/**
	* @Description: TODO 将传入的键/值对参数转换为NameValuePair参数集
	* @param paramsMap
	* @return
	* @author: A-Do
	* @date: 2015-7-20 上午11:47:20
	*/
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static List getParamsList(Map<Object,Object> paramsMap) {
		if (paramsMap == null || paramsMap.size() == 0) {
			return null;
		}
		List params = new ArrayList();
		for (Entry<Object,Object> map : paramsMap.entrySet()) {
			params.add(new BasicNameValuePair(map.getKey().toString().trim(), map.getValue().toString().trim()));
		}
		return params;
	}
	
		// requestRetryHandler : TODO  异常自动恢复处理, 使用HttpRequestRetryHandler接口实现请求的异常恢复
		private static HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() {
			// 自定义的恢复策略
			public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
				// 设置恢复策略，在发生异常时候将自动重试3次
				if (executionCount >= 3) {
					return false;
				}
				if (exception instanceof NoHttpResponseException) {
					return true;
				}
				if (exception instanceof SSLHandshakeException) {
					return false;
				}
				HttpRequest request = (HttpRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
				boolean idempotent = (request instanceof HttpEntityEnclosingRequest);
				if (!idempotent) {
					return true;
				}
				return false;
			}
		};
		// responseHandler : TODO 使用ResponseHandler接口处理响应，HttpClient使用ResponseHandler会自动管理连接的释放，解决了对连接的释放管理
		@SuppressWarnings({ "rawtypes"})
		private static ResponseHandler responseHandler = new ResponseHandler() {
			// 自定义响应处理
			public String handleResponse(HttpResponse response)	throws ClientProtocolException, IOException {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					String charset = EntityUtils.getContentCharSet(entity) == null ? "CHARSET_GBK" : EntityUtils.getContentCharSet(entity);
					return new String(EntityUtils.toByteArray(entity), charset);
				} else {
					return null;
				}
			}
		};
		
		
		/**
		* @Description: TODO 获取DefaultHttpClient实例
		* @param charset
		* @return
		* @author: A-Do
		* @date: 2015-7-20 下午1:28:13
		*/
		private static DefaultHttpClient getDefaultHttpClient(final String charset){
			DefaultHttpClient httpclient = new DefaultHttpClient();
			httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
			//模拟浏览器，解决一些服务器程序只允许浏览器访问的问题
			httpclient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)");
			httpclient.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, Boolean.FALSE);
			httpclient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, charset == null ? "CHARSET_GBK" : charset);
			httpclient.setHttpRequestRetryHandler(requestRetryHandler);
			return httpclient;
		}
		
		
		/**
		* @Description: TODO 释放HttpClient连接
		* @param hrb
		* @param httpclient
		* @author: A-Do
		* @date: 2015-7-20 下午1:28:00
		*/
		private static void abortConnection(final HttpRequestBase hrb, final HttpClient httpclient){
			if (hrb != null) {
				hrb.abort();
			}
			if (httpclient != null) {
				httpclient.getConnectionManager().shutdown();
			}
		}

}
